//: src/com/silvtar/io/StreamToolkit.java
/* 
 * Created by 朴晟宁 <piaosn@gmail.com> on 4/21/2013. 
 * Copyright (c) 2013 朴晟宁. All rights reserved.
 * 
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program;
 * 
 * *********************************************************************
 * 
 * Modify History:
 * Date        Version    Description
 * 4/24/2013   0.1        Create the class
 * 4/26/2013   0.2        Add some constructor. It can construct with 
 *                        <File>, <Connection> and <Server> now.
 * 5/11/2013   0.3        Rename the class to StreamToolkit. Add some 
 *                        function to read & write the stream. 
 * 5/25/2013   0.4        Add two functions into the class. writeBytes
 *                        and readLine
 * 
 */

package com.silvtar.io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.RandomAccessFile;
import java.io.Reader;
import java.io.Writer;
import java.net.Socket;

import com.silvtar.net.Server;

/**
 * 流工具箱类。可以把各种文件转换为流，提供一些常用的流相关操作。
 * 
 * @author 朴晟宁/Silvtar
 * @author piaosn@gmail.com
 * @version 0.4
 */
public class StreamToolkit {

    InputStream         inputStream;

    OutputStream        outputStream;

    DataInputStream     dataInputStream;

    DataOutputStream    dataOutputStream;
    
    Reader              reader;

    Writer              writer;

    BufferedReader      bufferedReader;

    BufferedInputStream bufferedInputStream;
    
    BufferedOutputStream bufferedOutputStream;

    RandomAccessFile    randomAccessFile;

    public void close() {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (writer != null) {
            try {
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (dataInputStream != null) {
            try {
                dataInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (dataOutputStream != null) {
            try {
                dataOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (outputStream != null) {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (dataInputStream != null) {
            try {
                dataInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (dataOutputStream != null) {
            try {
                dataOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    // ---------------------------- getter && setter ---------------------------

    public InputStream getInputStream() {

        if (null == inputStream) {
            StdOut.printWarningLog(this,
                    "The Value <inputStream> is null. It may make some problem.");
        }
        return inputStream;
    }

    public OutputStream getOutputStream() {

        if (null == outputStream) {
            StdOut.printWarningLog(this,
                    "The Value <outputStream> is null. It may make some problem.");
        }
        return outputStream;
    }

    public DataInputStream getDataInputStream() {

        if (null == dataInputStream) {
            StdOut.printWarningLog(this,
                    "The Value <dataInputStream> is null. It may make some problem.");
        }
        return dataInputStream;
    }

    public DataOutputStream getDataOutputStream() {

        if (null == dataOutputStream) {
            StdOut.printWarningLog(this,
                    "The Value <dataOutputStream> is null. It may make some problem.");
        }
        return dataOutputStream;
    }

    public Reader getReader() {

        if (null == reader) {
            StdOut.printWarningLog(this,
                    "The Value <reader> is null. It may make some problem.");
        }
        return reader;
    }

    public Writer getWriter() {

        if (null == writer) {
            StdOut.printWarningLog(this,
                    "The Value <writer> is null. It may make some problem.");
        }
        return writer;
    }

    // ---------------------------- 构造方法 ---------------------------

    // ============================== String ================================
    /**
     * 打开文件，并获取IO流。
     * 
     * @param fileName
     *            文件名
     * @param mode
     *            打开模式，只读 <r> 或读写 <rw>
     * @param append
     *            是否以追加模式打开文件。这个参数只在 mode = rw 时生效.
     */
    public StreamToolkit(String fileName, String mode, boolean append) {

        File file = new File(fileName);
        try {
            randomAccessFile = new RandomAccessFile(file, mode);
            if (file.exists()) {
                inputStream = new FileInputStream(file);
            }
            if (mode.equals("rw")) {
                outputStream = new FileOutputStream(file, append);
            }
        } catch (FileNotFoundException e) {
            StdOut.printErr("从 <file> = " + file.getAbsolutePath()
                    + " 获取流失败！文件不存在。");
            e.printStackTrace();
        }
        translate();
    }

    /**
     * 打开文件，并获取IO流。这个构造方法会覆写文件。
     * 
     * @param fileName
     *            文件
     * @param mode
     *            打开模式，只读 <r> 或读写 <rw>
     */
    public StreamToolkit(String fileName, String mode) {

        File file = new File(fileName);
        try {
            randomAccessFile = new RandomAccessFile(file, mode);
            if (file.exists()) {
                inputStream = new FileInputStream(file);
            }
            if (mode.equals("rw")) {
                outputStream = new FileOutputStream(file);
            }
        } catch (FileNotFoundException e) {
            StdOut.printErr("从 <file> = " + file.getAbsolutePath()
                    + " 获取流失败！文件不存在。");
            e.printStackTrace();
        }
        translate();
    }

    /**
     * 打开文件，并获取IO流。对于输出流，将以追加模式打开。
     * 
     * @param fileName
     *            文件
     */
    public StreamToolkit(String fileName) {

        File file = new File(fileName);
        try {
            randomAccessFile = new RandomAccessFile(file, "r");
            if (file.exists()) {
                inputStream = new FileInputStream(file);
            }

            outputStream = new FileOutputStream(file, true);
        } catch (FileNotFoundException e) {
            StdOut.printErr("从 <file> = " + file.getAbsolutePath()
                    + " 获取流失败！文件不存在。");
            e.printStackTrace();
        }
        translate();
    }

    // ============================== File ================================
    /**
     * 打开文件，并获取IO流。
     * 
     * @param file
     *            文件
     * @param mode
     *            打开模式，只读 <r> 或读写 <rw>
     * @param append
     *            是否以追加模式打开文件。这个参数只在 mode = rw
     *            时生效如果只想读取文件，应该使用追加模式。这样可以保证文件不被覆写。
     */
    public StreamToolkit(File file, String mode, boolean append) {

        try {
            randomAccessFile = new RandomAccessFile(file, mode);
            if (file.exists()) {
                inputStream = new FileInputStream(file);
            }
            if (mode.equals("rw")) {
                outputStream = new FileOutputStream(file, append);
            }
        } catch (FileNotFoundException e) {
            StdOut.printErr("从 <file> = " + file.getAbsolutePath()
                    + " 获取流失败！文件不存在。");
            e.printStackTrace();
        }
        translate();
    }

    /**
     * 打开文件，并获取IO流。这个构造方法会覆写文件。
     * 
     * @param file
     *            文件
     * @param mode
     *            打开模式，只读 <r> 或读写 <rw>
     */
    public StreamToolkit(File file, String mode) {

        try {
            randomAccessFile = new RandomAccessFile(file, mode);
            if (file.exists()) {
                inputStream = new FileInputStream(file);
            }
            if (mode.equals("rw")) {
                outputStream = new FileOutputStream(file);
            }
        } catch (FileNotFoundException e) {
            StdOut.printErr("从 <file> = " + file.getAbsolutePath()
                    + " 获取流失败！文件不存在。");
            e.printStackTrace();
        }
        translate();
    }

    /**
     * 打开文件，并获取IO流。对于输出流，将以追加模式打开。
     * 
     * @param file
     *            文件
     */
    public StreamToolkit(File file) {

        try {
            randomAccessFile = new RandomAccessFile(file, "r");
            if (file.exists()) {
                inputStream = new FileInputStream(file);
            }

            outputStream = new FileOutputStream(file, true);
        } catch (FileNotFoundException e) {
            StdOut.printErr("从 <file> = " + file.getAbsolutePath()
                    + " 获取流失败！文件不存在。");
            e.printStackTrace();
        }
        translate();
    }

    // ============================== Network ================================
    public StreamToolkit(Server server, int identifier) {

        Socket socket = server.getSocketList().get(identifier);
        try {
            this.inputStream = socket.getInputStream();
            this.outputStream = socket.getOutputStream();
        } catch (IOException e) {
            StdOut.printErr("从 <server.socketList[" + identifier + "]> = "
                    + socket.getInetAddress().getHostAddress() + " 获取流失败！");
            e.printStackTrace();
        }
        translate();
    }

    public StreamToolkit(Socket socket) {

        try {
            this.inputStream = socket.getInputStream();
            this.outputStream = socket.getOutputStream();
        } catch (IOException e) {
            StdOut.printErr("从 <socket> = "
                    + socket.getInetAddress().getHostAddress() + "获取流失败！");
            e.printStackTrace();
        }
        translate();
    }

    // ============================== Others ================================
    public StreamToolkit(InputStream inStream, OutputStream outStream) {

        this.inputStream = inStream;
        this.outputStream = outStream;
        translate();
    }

    public StreamToolkit(InputStream inStream) {

        this.inputStream = inStream;
        translate();
    }

    public StreamToolkit(OutputStream outStream) {

        this.outputStream = outStream;
        translate();
    }

    // ---------------------------- 为成员变量赋值 ---------------------------
    public void translate() {

        if (null != inputStream) {
            dataInputStream = new DataInputStream(inputStream);
            reader = new InputStreamReader(inputStream);
            getBufferedReader();
        }
        if (null != outputStream) {
            dataOutputStream = new DataOutputStream(outputStream);
            writer = new OutputStreamWriter(outputStream);
        }
    }

    public BufferedInputStream getBufferedInputStream() {
        if (bufferedInputStream == null) {
            bufferedInputStream = new BufferedInputStream(inputStream);
        }
        return bufferedInputStream;
    }

    public BufferedReader getBufferedReader() {
        if (bufferedReader == null) {
            bufferedReader = new BufferedReader(new InputStreamReader(
                    getBufferedInputStream()));
        }
        return bufferedReader;
    }

    public void makeDataStreamBuffered() {
        dataInputStream = new DataInputStream(new BufferedInputStream(inputStream));
        dataOutputStream = new DataOutputStream(new BufferedOutputStream(outputStream));
    }
    
    
    
    // ============================== 实用方法 ================================
    public void writeBytes(String str) {
        if (dataOutputStream != null) {
            try {
                dataOutputStream.writeBytes(str);
            } catch (IOException e) {
                StdOut.printErr("writeBytes false");
                e.printStackTrace();
            }
        } else {
            StdOut.printErr("dataOutputStram is null");
        }
    }

    public String readLine() {
        String str = null;
        if (bufferedReader != null) {
            try {
                str = bufferedReader.readLine();
            } catch (IOException e) {
                StdOut.printErr("readLine false");
                e.printStackTrace();
            }
        } else {
            StdOut.printErr("bufferedReader is null");
        }
        return str;
    }

    public void writeUTF(String str) {
        if (dataOutputStream != null) {
            try {
                dataOutputStream.writeUTF(str);
            } catch (IOException e) {
                StdOut.printErr("WriteUTF false");
                e.printStackTrace();
            }
        } else {
            StdOut.printErr("dataOutputStram is null");
        }
    }

    public String readUTF() {
        String str = null;
        if (dataInputStream != null) {
            try {
                str = dataInputStream.readUTF();
            } catch (IOException e) {
                StdOut.printErr("ReadUTF false");
                e.printStackTrace();
            }
        } else {
            StdOut.printErr("dataInputStram is null");
        }
        return str;
    }

    public void writeObject(Object obj) {
        try {
            ObjectOutputStream objOutStream = new ObjectOutputStream(
                    getOutputStream());
            objOutStream.writeObject(obj);
            objOutStream.flush();

        } catch (IOException e) {
            StdOut.printErr("Open ObjectOutputStream Err");
            e.printStackTrace();
        }
    }

    public Object readObject() {
        Object obj = null;
        try {
            ObjectInputStream objInStream = new ObjectInputStream(
                    getInputStream());
            obj = objInStream.readObject();

        } catch (IOException e) {
            StdOut.printErr("Open ObjectInputStream Err");
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            StdOut.printErr("Read Object false");
            e.printStackTrace();
        }
        return obj;
    }
}
